#include "mm.h"
#include "bgc/include/gc.h"
#include "package.h"
#include "error.h"
#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

CFSymbol * mm_alloc_t;
CFSymbol * mm_alloc_nil;
char * XTypeNames[] = {"Integer", "List", "Symbol","Decimal","Vector","Character","String","Caller"};

static CFSymbol ** mm_hash_symbol_table;
#define HASH_SYMBOL_TABLE_MAX_SIZE 128

void MMInit(void)
{

  /* boehm garbage collector initiation */
  GC_INIT();
  PKGInit();
  mm_alloc_t   = MMSymbol("T", NULL);
  mm_hash_symbol_table = (CFSymbol **) malloc (sizeof(CFSymbol *) * 
					       HASH_SYMBOL_TABLE_MAX_SIZE);
  bzero(mm_hash_symbol_table, HASH_SYMBOL_TABLE_MAX_SIZE);
  /* MSG: change this to NULL? */
  mm_alloc_nil = MMSymbol("NIL", NULL);
	
  /* boing,  boing!! symbols tends to have the same value and can be eq'ed*/
}

void MMDelete (void)
{
  free(mm_hash_symbol_table);
}

CFCons * MMCons(void * car, void * cdr)
{
  CFCons * obj = (CFCons *) GC_MALLOC (sizeof(CFCons));
  obj->type = CFCONS_TYPE;
  obj->car = car;
  obj->cdr = cdr;
  return obj;
}

CFSymbol * MMSymbol(char * string, char * package)
{
		
  CFSymbol * obj = (CFSymbol *) GC_MALLOC (sizeof(CFSymbol));
  CFPackage * temp;
  char errorCase[1024];
		
  obj->type = CFSYMBOL_TYPE;
  obj->string = (char *) GC_MALLOC (sizeof(char) * strlen(string));
  obj->hashvalue = NULL;
  strcpy(obj->string,string);
  if(package == NULL || !strcmp(package, PKGCurrentPackageName))
    obj->package = PKGCurrentPackage;
  else
    {
      temp = PKGGetPackage(package);
      if (PKGGetPackage(package) == NULL) {
	sprintf(errorCase,"Package '%s' not found", package);
	ERRORThrow(errorCase);	
      } else
	obj->package = PKGGetPackage(package);
    }
  return obj;
}

CFSymbol * MMSymbolNotSeperated (char * string)
{
  char pacote[1024];
  char simbolo[1024];
  int lswitch=0;
  int pLocal=0;
  int sLocal=0;
  int i=0;
  while (string[i] != '\0')
    {
      if(string[i] == ':')
	{lswitch = 1; i++;} else
	if(lswitch)
	  simbolo[sLocal++] = string[i++];
	else
	  pacote[pLocal++] = string[i++];
    }
  simbolo[sLocal] = '\0';
  pacote[pLocal] = '\0';
  if (! lswitch)
    return MMSymbol( pacote, NULL); else
    if (! pLocal)
      return MMSymbol (simbolo, "Keyword"); else
      return MMSymbol (simbolo, pacote);
}

CFInteger * MMInteger(int i)
{
  CFInteger * obj = (CFInteger *) GC_MALLOC_ATOMIC (sizeof(CFInteger));
  obj->type = CFINTEGER_TYPE;
  obj->number = i;
  return obj;
}

CFDouble * MMDouble(double d)
{
  CFDouble * obj = (CFDouble *) GC_MALLOC_ATOMIC (sizeof(CFDouble));
  obj->type = CFFLOAT_TYPE;
  obj->number = d;
  return obj;
}

CFVector * MMVector(int size)
{
  CFVector * obj = (CFVector *) GC_MALLOC (sizeof(CFVector));
  obj->type = CFVECTOR_TYPE;
  obj->size = size;
  obj->cells = (void *) GC_MALLOC_ATOMIC (sizeof(void *) * size);
  bzero (obj->cells,size * sizeof(void *));
  return obj;
}

CFString* MMString(char * string)
{
  CFString * obj = (CFString *) GC_MALLOC (sizeof(CFString));
  obj->type = CFSTRING_TYPE;
  obj->length = strlen(string);		
  obj->string = GC_MALLOC_ATOMIC (sizeof(char) * obj->length);		
  strcpy (obj->string, string);
  /*TODO: this may be speedup*/
  return obj;
}

CFCharacter * MMChar(char character)
{
  CFCharacter * obj = (CFCharacter *) GC_MALLOC_ATOMIC (sizeof(CFCharacter));
  obj->type = CFCHARACTER_TYPE;
  obj->character = character;
  return obj;
}


CFPackage * MMPackage (char * name){
  CFPackage * object = (CFPackage *) GC_MALLOC (sizeof(CFPackage));
  object->name = (char *) GC_MALLOC_ATOMIC (sizeof(char) * strlen(name));
  strcpy(object->name, name);
  object->next = NULL;
  return object;
}

CFCaller * MMCaller(void * sexpr)
{
  CFCaller * obj = (CFCaller *) GC_MALLOC (sizeof(CFCaller));
  obj->type = CFCALLER_TYPE;
  obj->length = 0;
  obj->sexpr = sexpr; 
  return obj;
}
